package encaps.utils.search;

import encaps.action.BasicSearchAction;
import encaps.entities.OrderType;
import encaps.entities.Role;
import encaps.resources.Labels;
import encaps.resources.Response;
import encaps.utils.SystemException;
import encaps.utils.XMLHelper;
import java.util.Collection;
import java.util.Iterator;
import org.jdom.Element;

public abstract class Searcher {

    protected String basicSearchHeaderPattern;

    public Element getResult(SearchContext context) throws SystemException {
        int pageCount = getPageCount(context);
        context.setPageCount(pageCount);
        Collection searchResult = find(context);
        Element result = toXMLElement(searchResult, context);
        return result;
    }

    public Element toXMLElement(Collection searchResult, SearchContext context) {
        Element e = XMLHelper.createElement(Response.TABLE);
        //Создаем заголовок страницы
        String header = null;
        if (context.isBasicSearch()) {
            String searchParameter = context.getSearchParameter(BasicSearchAction.SEARCH_PARAMETER);
            header = String.format(basicSearchHeaderPattern, searchParameter);
        } else {
            header = Labels.getLabel(Labels.FOUND_RESULTS_HEADER);
        }
        XMLHelper.addChild(e, Response.HEADER, header);
        //Создаем заголовки столбцов таблиц
        Element headers = headersToXMLElement();
        XMLHelper.addChild(e, headers);
        //Заполняем таблицу
        Role userRole = context.getUserRole();
        XMLHelper.addChild(e, searchResultToTableRows(searchResult, userRole));
        //Заполняем информацию, необходимую для пагинации
        Element searchingParameters = searchParametersToXMLElement(context);
        XMLHelper.addChild(e, searchingParameters);
        return e;
    }

    private int getPageCount(SearchContext context) throws SystemException {
        int recordCount = getFoundRecordsCount(context);
        int recordsPerPage = context.getRecordsPerPage();
        int pageCount = recordCount / recordsPerPage;
        if (recordCount % recordsPerPage > 0) {
            pageCount++;
        }
        return pageCount;
    }

    protected Element searchParametersToXMLElement(SearchContext context) {
        //Заполняем информацию, необходимую для пагинации
        Element searchingParameters = XMLHelper.createElement(Response.SEARCHING_PARAMETERS);
        int pageCount = context.getPageCount();
        XMLHelper.addChild(searchingParameters, Response.PAGE_COUNT, pageCount);
        int currentPage = context.getPage();
        XMLHelper.addChild(searchingParameters, Response.CURRENT_PAGE, currentPage);

        //Задание параметров поиска
        Element parameters = XMLHelper.createElement(Response.PARAMETERS);
        Iterator<String> parameterNames = context.getSearchParametersIterator();
        while (parameterNames.hasNext()) {
            String parameterName = parameterNames.next();
            String parameterValue = context.getSearchParameter(parameterName);
            Element parameter = XMLHelper.createElement(Response.PARAMETER);
            XMLHelper.addChild(parameter, Response.NAME, parameterName);
            XMLHelper.addChild(parameter, Response.VALUE, parameterValue);
            XMLHelper.addChild(parameters, parameter);
        }
        XMLHelper.addChild(searchingParameters, parameters);
        String entityType = context.getEntityType();
        XMLHelper.addChild(searchingParameters, Response.ENTITY_TYPE, entityType);
        String actionName = context.getActionName();
        XMLHelper.addChild(searchingParameters, Response.ACTION_NAME, actionName);

        //Информация для сортировки
        String orderColumn = context.getOrderColumn();
        XMLHelper.addChild(searchingParameters, Response.ORDER_COLUMN, orderColumn);
        OrderType orderType = context.getOrderType();
        XMLHelper.addChild(searchingParameters, Response.ORDER_TYPE, orderType.toString());

        return searchingParameters;
    }

    protected abstract Element headersToXMLElement();

    protected abstract Element searchResultToTableRows(Collection result, Role userRole);

    protected abstract Collection find(SearchContext context) throws SystemException;

    protected abstract int getFoundRecordsCount(SearchContext context) throws SystemException;
}
